package com.github.hgkmail.hello.interview.multithread;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

//AQS：抽象队列同步器，其中 queue 指的是 CLH双端队列（双向链表实现的）
public class MyAQS {

    //实现互斥量，state=0 未被占用，state=1 被占用，用AQS提供的方法compareAndSetState()操作state
    public static class MyMutex extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            return compareAndSetState(0, 1);
        }

        @Override
        protected boolean tryRelease(int arg) {
            return compareAndSetState(1, 0);
        }
    }

    //更好地实现互斥量，AQS作为一个helper class，类自身实现Lock接口
    public static class MyMutex2 implements Lock {

        //helper class
        private static class Sync extends AbstractQueuedSynchronizer {
            // Reports whether in locked state
            protected boolean isHeldExclusively() {
                return getState() == 1;
            }

            // Acquires the lock if state is zero
            public boolean tryAcquire(int acquires) {
                assert acquires == 1; // Otherwise unused
                if (compareAndSetState(0, 1)) {
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
                return false;
            }

            // Releases the lock by setting state to zero
            protected boolean tryRelease(int releases) {
                assert releases == 1; // Otherwise unused
                if (getState() == 0) throw new IllegalMonitorStateException();
                setExclusiveOwnerThread(null);
                setState(0);
                return true;
            }

            // Provides a Condition
            Condition newCondition() { return new ConditionObject(); }
        }

        // sync实现全部锁逻辑，The sync object does all the hard work. We just forward to it.
        private final Sync sync = new Sync();

        public void lock()                { sync.acquire(1); }
        public boolean tryLock()          { return sync.tryAcquire(1); }
        public void unlock()              { sync.release(1); }
        public Condition newCondition()   { return sync.newCondition(); }
        public boolean isLocked()         { return sync.isHeldExclusively(); }
        public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }
        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException {
            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
        }
    }

    //简单实现信号量
    //1.必须使用CAS，且判断CAS返回值是否成功（CAS在多线程下经常替换state失败！）
    //2.推荐使用自旋等待一会 for(;;){}
    //3.默认都是非公平锁，公平锁的实现：判断hasQueuedPredecessors()返回值，如果等待队列中该线程前面还有线程，那么不让它获取到锁，直接返回失败
    public static class MySemaphore extends AbstractQueuedSynchronizer {
        private final int num;

        public MySemaphore(int n) {
            num=n; //最多允许几个线程访问共享对象
            setState(0);
        }

        //返回负数获取失败，返回0获取到最后一个机会，返回正数获取成功且后面还有机会获取
        @Override
        protected int tryAcquireShared(int arg) {
            for (;;) { //自旋（推荐）
                assert arg==1;
                int state=getState();
                int exist=state+arg;
                if (exist>num) {
                    return -1;
                }
                if (compareAndSetState(state, exist)) { //重要：必须判断CAS的返回值，多线程下CAS经常失败！
                    return num-exist;
                }
            }
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            for (;;) { //自旋（推荐）
                assert arg==1;
                int state=getState();
                if(compareAndSetState(state, state-arg)) { //重要：必须判断CAS的返回值，多线程下CAS经常失败！
                    return true;
                }
            }
        }
    }

    //同步stack，基于synchronized的条件队列
    static class SyncStack extends LinkedList<Integer> {
        private final Object syncObject=new Object(); //可以用this代替
        volatile boolean stackEmpty = true; //volatile变量 或者 原子类型AtomicXXX 很适合做条件，保证线程一写多读的可见性（数据一致性）

        public void syncOfferLast(int n) {
            synchronized (syncObject) {
                offerLast(n);
                stackEmpty=false;
//                syncObject.notify(); //通知条件队列的一个线程（随机挑选）
                syncObject.notifyAll(); //通知条件队列的所有线程（清空条件队列）
            }
        }

        public Integer syncPollLast() throws InterruptedException {
            synchronized (syncObject) {
                while(stackEmpty) { //对于条件队列condition，自旋是必须的
                    syncObject.wait(); //释放锁并进入条件队列
                }
                //条件满足且获取到锁，放手干活
                Integer res = pollLast();
                if (isEmpty()) {
                    stackEmpty=true;
                }
                return res;
            }
        }
    }

    //同步队列，基于 AQS 和 ConditionObject
    static class SyncQueue extends LinkedList<Integer> {
        //helper class
        static class Sync extends AbstractQueuedSynchronizer {
            @Override
            protected boolean tryAcquire(int arg) {
                assert arg==1;
                if (compareAndSetState(0, 1)) {
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
                return false;
            }

            @Override
            protected boolean tryRelease(int arg) {
                assert arg==1;
                if (compareAndSetState(1, 0)) {
                    setExclusiveOwnerThread(null);
                    return true;
                }
                return false;
            }

            /**
             * 使用ConditionObject需要override这个方法
             * 是否被独占， 有两种表示方式
             *  1. 可以根据状态，state=1表示锁被占用，0表示空闲
             *  2. 可以根据当前独占锁的线程来判断，即getExclusiveOwnerThread()!=null 表示被独占
             */
            @Override
            protected boolean isHeldExclusively() {
                return getState()==1;
            }

            //创建关联的条件队列
            //为什么 ConditionObject 可以知道等待队列是哪个AQS呢？因为Node知道，ConditionObject和AQS是解耦的，通过Node进行关联
            final Condition newCondition() {
                return new ConditionObject();
            }
        }

        private final int capacity;
        private final Sync sync;
        private final Condition notEmpty; //注意：condition使用 await 和 signal/signalAll
        private final Condition notFull;

        public SyncQueue(int cap) {
            capacity = cap;
            sync=new Sync();
            notEmpty=sync.newCondition();
            notFull=sync.newCondition();
        }

        public void syncOfferLast(int a) throws InterruptedException {
            sync.acquire(1); //AQS只有活动线程才能获取到锁
            try {
                while (size()>=capacity) { //条件不满足，自旋
                    notFull.await(); //释放锁，进入条件队列
                }
                //条件满足
                offerLast(a);
                notEmpty.signalAll();
            } finally {
                sync.release(1);
            }
        }

        public Integer syncPollFirst() throws InterruptedException {
            sync.acquire(1);
            try {
                while (isEmpty()) { //条件不满足，自旋
                    notEmpty.await(); //释放锁，进入条件队列
                }
                //条件满足
                Integer res=pollFirst();
                notFull.signalAll();
                return res;
            } finally {
                sync.release(1);
            }
        }

    }


}
